# -*- coding: utf-8 -*-
import platform
import random
import subprocess
import time
import logging
import argparse
from datetime import datetime, timedelta
from typing import Tuple

from appium import webdriver
# from appium.options.android import UiAutomator2Options
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException, TimeoutException

logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
logger = logging

APP = "XHS"

app_package_map = {
    "XHS": ("com.xingin.xhs", ".index.v2.IndexActivityV2")
}


class XHSAppiumOperate:
    def __init__(self, **kwargs):
        self.screen_width = None
        self.screen_height = None
        self.targetUrl = self.extract_xhs_url(kwargs.get("targetUrl"))
        self.text = kwargs.get("text").replace("\\n", "\n")
        self.keyword = kwargs.get("keyWord").replace("\\n", "\n")
        self.deviceName = kwargs.get("deviceName")
        self.appium_url = kwargs.get("appium_url")
        self.platformVersion = kwargs.get("platformVersion")
        self.systemPort = kwargs.get("systemPort")
        self.adbPort = kwargs.get("adbPort")

        self.driver = None
        self.max_retries = 3
        self.failure_count = 0

    def run(self):
        while self.max_retries > 0:
            try:
                if self.driver:
                    self.driver.quit()
                self.connection()
                logger.info(f"设备 {self.deviceName} 连接成功")
                time.sleep(3)

                logger.info("开始执行小红书评论任务...")
                self.script()

                break
            except Exception as e:
                logger.error(f"发生异常: {e}")
                self.failure_count += 1
                self.max_retries -= 1
                if self.max_retries == 0:
                    self.normal_end()
                    raise Exception("任务失败")
        logger.info("任务结束")

    @staticmethod
    def execute_adb_command(adb_command):
        """
        执行单条 ADB 命令

        :param adb_command: 完整的 ADB 命令字符串
        :return: 命令执行结果（stdout）
        """
        try:
            logger.info(f"执行 ADB 命令: {adb_command}")
            result = subprocess.run(
                adb_command,
                shell=True,
                check=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE
            )
            logger.info(f"命令执行成功: {adb_command}")
            return result.stdout.decode('utf-8')
        except subprocess.CalledProcessError as e:
            logger.error(f"命令执行失败: {adb_command}")
            logger.error(f"错误信息: {e.stderr.decode('utf-8')}")

    def initialize_device_settings(self):
        """
        执行设备初始化所需的 ADB 命令
        """
        logger.info("开始初始化设备设置")

        commands = [
            f"adb -s {self.deviceName} -P {self.adbPort} shell settings put global adb_keep_usb_enabled 1",
            f"adb -s {self.deviceName} -P {self.adbPort} shell settings put global miui_optimization 0",
            f"adb -s {self.deviceName} -P {self.adbPort} shell settings put global tcp_keepalive 1",
            f"adb -s {self.deviceName} -P {self.adbPort} shell dumpsys battery unplug",
            f"adb -s {self.deviceName} -P {self.adbPort} shell pm enable io.appium.uiautomator2.server",
            f"adb -s {self.deviceName} -P {self.adbPort} shell pm enable io.appium.uiautomator2.server.test",
            f"adb -s {self.deviceName} -P {self.adbPort} shell settings put global background_process_limit 5",
            f"adb -s {self.deviceName} -P {self.adbPort} shell am set-standby-bucket io.appium.uiautomator2.server ACTIVE",
            f"adb -s {self.deviceName} -P {self.adbPort} shell pm trim-caches 500M",
            f"adb -s {self.deviceName} -P {self.adbPort} shell pm clear io.appium.uiautomator2.server",
            f"adb -s {self.deviceName} -P {self.adbPort} shell pm clear io.appium.uiautomator2.server.test",
            f"adb -s {self.deviceName} -P {self.adbPort} shell input keyevent KEYCODE_CLEAR"
        ]

        for cmd in commands:
            try:
                self.execute_adb_command(cmd)
            except Exception as e:
                logger.error(f"执行命令失败: {cmd}")
                logger.error(f"错误详情: {e}")

    def connection(self):
        self.initialize_device_settings()
        desired_caps = {
            "platformName": "Android",
            "platformVersion": self.platformVersion,
            "deviceName": self.deviceName,
            "udid": self.deviceName,
            "automationName": "UiAutomator2",
            "appPackage": app_package_map[APP][0],
            "appActivity": app_package_map[APP][1],
            "noReset": True,
            "fullReset": False,
            "systemPort": int(self.systemPort),
            "adbPort": int(self.adbPort),
            "appWaitForLaunch": True,
            "noSign": True,
            "autoLaunch": True,
            "newCommandTimeout": 180,
            "skipLogcatCapture": True,
            "disableWindowAnimation": True,
            "disableAndroidWatchers": True,
            "adbExecTimeout": 30000,
            "uiautomator2ServerInstallTimeout": 60000,
            "skipDeviceInitialization": True,
        }
        self.driver = webdriver.Remote(self.appium_url, desired_caps)
        # self.driver = webdriver.Remote(self.appium_url, options=UiAutomator2Options().load_capabilities(desired_caps))
        self.screen_width, self.screen_height = self.get_window_size()

    def script(self):
        logger.info("开始执行短链评论任务")

        # 1. 打开链接
        self.open_link_in_browser(self.targetUrl)
        time.sleep(5)  # 等待页面加载
        # 2. 点击「在小红书打开」按钮
        self.click_open_with_xhs()

        # 3. 等待页面加载完成
        time.sleep(2)

        self.leave_comment()

        time.sleep(5)

        # 5. 结束本次操作
        # self.normal_end()
        time.sleep(5)

    def expand_reply_image_text_if_exists(self, recycler_view):
        try:
            # 查找并点击文本以“展开”开头的元素
            expand_reply_element = recycler_view.find_element(
                AppiumBy.XPATH,
                '//android.widget.TextView[starts-with(@text,"展开")]')
            expand_reply_element.click()
            logger.info("点击了'展开回复'元素")
        except NoSuchElementException:
            logger.info("未找到'展开回复'元素")

    def expand_reply_video_if_exists(self, recycler_view):
        try:
            # 查找并点击文本以“展开”开头的元素
            expand_reply_element = recycler_view.find_element(
                AppiumBy.XPATH,
                '//android.widget.Button[starts-with(@text,"展开")]')
            expand_reply_element.click()
            logger.info("点击了'展开回复'元素")
        except NoSuchElementException:
            logger.info("未找到'展开回复'元素")

    def find_and_compare_text_in_view(self, view, comment_callback):
        try:

            # 获取所有 TextView 元素
            items = view.find_elements(AppiumBy.XPATH, "./*")

            logger.info(f"找到 {len(items)} 个 RecyclerView 子项")

            for i, item in enumerate(items):
                logger.info(f"第 {i + 1} 个子项内容如下：")
                # 3. 在当前 item 中查找所有 TextView
                text_views = item.find_elements(AppiumBy.CLASS_NAME, "android.widget.TextView")
                for tv in text_views:
                    try:
                        text = tv.text
                        if text:
                            # logger.info(f"TextView 文本: {text}")

                            if any(kw in text for kw in self.keyword.split('\n')):
                                logger.info(f"找到包含关键词的文本: {text}")
                                # 如果有回调函数，立即执行评论操作
                                if comment_callback and callable(comment_callback):
                                    comment_callback(tv)  # 调用回调函数
                    except Exception as e:
                        logger.warning(f"读取 TextView 内容失败")
                        continue
        except Exception as e:
            logger.error(f"在 RecyclerView 中查找文本时发生错误: {e}")

    def process_video_recycler_view(self, ):
        # 视频评论区自动化评论逻辑

        def comment_action_callback(text_view):
            # 回调函数
            text = self.text.split('\n')

            comment_text = random.choice(text)
            try:
                text_view.click()
                time.sleep(1)

                # 输入评论内容
                input_box = self.find_element_with_retry(
                    by=AppiumBy.XPATH,
                    value='//android.widget.EditText[@resource-id="com.xingin.xhs:id/0_resource_name_obfuscated"]',
                    timeout=5
                )
                input_box.send_keys(comment_text)

                # 点击发送按钮
                send_button = self.find_element_with_retry(
                    by=AppiumBy.XPATH,
                    value='//android.widget.TextView[@text="发送"]',
                    timeout=5
                )
                send_button.click()
                logger.info("评论成功！")
            except Exception as e:
                logger.error(f"通过回调评论失败: {e}")

        while True:

            view_group = self.find_element_with_retry(
                by=AppiumBy.XPATH,
                value='(//android.widget.FrameLayout[@resource-id="com.xingin.xhs:id/0_resource_name_obfuscated"])[5]',
                timeout=5
            )

            # 尝试展开回复
            self.expand_reply_video_if_exists(view_group)

            view_group = self.find_element_with_retry(
                by=AppiumBy.XPATH,
                value='(//android.widget.FrameLayout[@resource-id="com.xingin.xhs:id/0_resource_name_obfuscated"])[5]',
                timeout=5
            )
            # 扫描评论区，并且进行评论
            self.find_and_compare_text_in_view(view_group, comment_action_callback)

            # 滚动页面
            self.swipe_to_next(start_y_ratio=0.8, end_y_ratio=0.65)

            # 重新获取 RecyclerView（滚动后可能需要重新定位）
            try:
                self.find_element_with_retry(by=AppiumBy.ANDROID_UIAUTOMATOR,
                                             value='new UiSelector().description("已到底")',
                                             timeout=5)
                logger.info("已到底")
                break
            except NoSuchElementException:
                logger.info("未到底")

    def process_image_text_recycler_view(self, ):
        # 图文评论区自动化回复逻辑
        def comment_action_callback(text_view):
            # 回调函数
            text = self.text.split('\n')

            comment_text = random.choice(text)
            try:
                text_view.click()
                time.sleep(1)

                # 输入评论内容
                input_box = self.find_element_with_retry(
                    by=AppiumBy.XPATH,
                    value='//android.widget.EditText[@resource-id="com.xingin.xhs:id/0_resource_name_obfuscated"]',
                    timeout=5
                )
                input_box.send_keys(comment_text)

                # 点击发送按钮
                send_button = self.find_element_with_retry(
                    by=AppiumBy.XPATH,
                    value='//android.widget.TextView[@text="发送"]',
                    timeout=5
                )
                send_button.click()
                logger.info("评论成功！")
            except Exception as e:
                logger.error(f"通过回调评论失败: {e}")

        while True:
            recycler_view = self.find_element_with_retry(
                by=AppiumBy.XPATH,
                value='//androidx.recyclerview.widget.RecyclerView[@resource-id="com.xingin.xhs:id/0_resource_name_obfuscated"]',
                timeout=5,
            )

            # 尝试展开回复
            self.expand_reply_image_text_if_exists(recycler_view)
            recycler_view = self.find_element_with_retry(
                by=AppiumBy.XPATH,
                value='//androidx.recyclerview.widget.RecyclerView[@resource-id="com.xingin.xhs:id/0_resource_name_obfuscated"]',
                timeout=5,
            )
            # 在 RecyclerView 中查找包含关键词的 TextView
            self.find_and_compare_text_in_view(recycler_view, comment_action_callback)

            # 滚动页面
            self.swipe_to_next(start_y_ratio=0.8, end_y_ratio=0.6)

            # 重新获取 RecyclerView（滚动后可能需要重新定位）
            try:
                self.find_element_with_retry(by=AppiumBy.ANDROID_UIAUTOMATOR,
                                             value='new UiSelector().description("已到底")',
                                             timeout=5)
                logger.info("已到底")
                break
            except NoSuchElementException:
                logger.info("未到底")

    def leave_comment(self):
        """
        在当前视频或者笔记页面输入评论内容并提交
        :param comment_text: 要评论的内容
        """
        try:
            logger.info("开始分析内容是图文还是视频")
            stop_button = self.find_element_with_retry(
                by=AppiumBy.XPATH,
                value='//android.view.ViewGroup[@content-desc="暂停"]',
                timeout=2
            )
            stop_button.click()
            logger.info("进入【视频动态】页面")
            # 展开视频评论区
            comment_button = self.find_element_with_retry(by=AppiumBy.XPATH,
                                                          value='//android.widget.Button[starts-with(@content-desc,"评论")]',
                                                          timeout=5)
            comment_button.click()

            time.sleep(1)

            # 新增处理逻辑
            max_retries = 2
            for attempt in range(max_retries + 1):
                try:
                    self.process_video_recycler_view()
                    logger.info("成功查看视频评论区")
                    break
                except Exception as e:
                    if attempt < max_retries:
                        logger.warning(f"查看视频评论区 失败，第 {attempt + 1} 次重试...")
                        time.sleep(3)  # 等待 3 秒后重试
                    else:
                        logger.error(f"查看视频评论区 失败，已达到最大重试次数 ({max_retries})，错误: {e}")

        except Exception as e:
            logger.warning("播放按钮未找到，可能是笔记页面")
            logger.info("进入【图文笔记】页面")

            self.swipe_to_next()

            # 新增处理逻辑
            max_retries = 2
            for attempt in range(max_retries + 1):
                try:
                    self.process_image_text_recycler_view()
                    logger.info("成功查看图文评论区")
                    break
                except Exception as e:
                    if attempt < max_retries:
                        logger.warning(f"查看图文评论区 失败，第 {attempt + 1} 次重试...")
                        time.sleep(3)  # 等待 3 秒后重试
                    else:
                        logger.error(f"查看图文评论区 失败，已达到最大重试次数 ({max_retries})，错误: {e}")

        time.sleep(2)

    def click_open_with_xhs(self):
        """
        在浏览器中点击「在小红书打开」按钮
        """
        max_retries = 3
        for attempt in range(max_retries + 1):
            try:
                xhs_button = WebDriverWait(self.driver, 3).until(
                    EC.element_to_be_clickable((AppiumBy.XPATH, '//android.widget.TextView[contains(@text, "打开")]'))
                )
                xhs_button.click()
                logger.info("成功点击【App内打开】")
                time.sleep(3)
                return  # 成功点击后退出循环
            except Exception as e:
                if attempt < max_retries:
                    logger.error(f"点击「App内打开」失败，第 {attempt + 1} 次重试... 错误: {e}")
                    time.sleep(1)  # 等待1秒后重试
                else:
                    logger.error(f"点击「App内打开」失败，已达到最大重试次数 ({max_retries})，错误: {e}")
                    raise Exception("点击「App内打开」失败")
    def open_link_in_browser(self, url):
        """
        使用设备默认浏览器打开指定链接
        :param url: 需要打开的网页链接
        """
        logger.info(f"尝试使用默认浏览器打开链接: {url}")
        try:
            # 使用 adb 命令启动浏览器并访问链接
            subprocess.run([
                'adb', '-s', self.deviceName,
                '-P', self.adbPort,
                'shell', 'am', 'start',
                '-a', 'android.intent.action.VIEW',
                '-d', url
            ], check=True)
        except Exception as e:
            logger.error(f"打开链接失败: {e}")
            raise

    def swipe_to_next(self, start_y_ratio=0.8, end_y_ratio=0.3):
        """
        向上滑动屏幕
        :param start_y_ratio: 起始 Y 坐标比例（相对于屏幕高度）
        :param end_y_ratio: 结束 Y 坐标比例（相对于屏幕高度）
        """
        self.driver.swipe(
            self.screen_width / 2,
            self.screen_height * start_y_ratio,
            self.screen_width / 2,
            self.screen_height * end_y_ratio,
            100
        )

    def extract_xhs_url(self, url_text):
        """
        从文本中提取小红书链接
        :param url_text: 包含链接的文本
        :return: 提取到的链接或原始链接
        """
        import re

        # 检查是否是正常的URL格式
        if url_text.startswith(('http://', 'https://')):
            return url_text

        # 如果是包含口令信息的文本，尝试提取其中的链接
        # 匹配小红书的各种链接格式:
        # 1. http://xhslink.com/...
        # 2. https://www.xiaohongshu.com/...
        url_patterns = [
            r'http[s]?://xhslink\.com/[^\s]+',
            r'http[s]?://www\.xiaohongshu\.com/[^\s]+'
        ]

        for pattern in url_patterns:
            match = re.search(pattern, url_text)
            if match:
                extracted_url = match.group(0)
                logger.info(f"从文本中提取到链接: {extracted_url}")
                return extracted_url

        # 如果没有找到链接，返回原始文本
        logger.warning(f"未在文本中找到链接，使用原始文本: {url_text}")
        return url_text

    def find_element_with_retry(self, by, value, timeout=5):
        try:
            element = WebDriverWait(self.driver, timeout).until(
                EC.presence_of_element_located((by, value))
            )
            return element
        except TimeoutException:
            raise NoSuchElementException(f"找不到元素: {value}")

    def get_window_size(self):
        size = self.driver.get_window_size()
        return size['width'], size['height']

    def normal_end(self):
        logger.info("返回首页并退出")
        self.driver.press_keycode(3)  # HOME 键
        self.driver.quit()


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('-j', '--job_id', dest='job_id', type=str, default=None, required=True, help='target job_id')
    parser.add_argument('-u', '--appium_url', dest='appium_url', type=str, default=None, help='target appium_url')
    parser.add_argument('-d', '--deviceName', dest='deviceName', type=str, default=None, help='target deviceName')
    parser.add_argument('-s', '--systemPort', dest='systemPort', type=str, default=None, help='target systemPort')
    parser.add_argument('-a', '--adbPort', dest='adbPort', type=str, default=None, help='target adbPort')
    parser.add_argument('-p', '--platformName', dest='platformName', type=str, default=None, help='target platformName')
    parser.add_argument('-ver', '--platformVersion', dest='platformVersion', type=str, default=None,
                        help='target platformVersion')
    parser.add_argument('-v', '--variables', dest='variables', type=str, default='{}', help='target variables')
    parser.add_argument('-accountId', '--accountId', dest='accountId', type=str, default="000", help='target accountId')
    parser.add_argument('-targetUrl', '--targetUrl', type=str, required=True)
    parser.add_argument('-text', '--text', type=str, required=True, default="私我\n看我的空间，分享给你")
    parser.add_argument('-keyWord', '--keyWord', type=str, required=True,
                        default="哪款\n哪买\n还有吗\n怎么卖\n怎么买\n多少钱\n多钱\n有吗\n好看\n哪里")

    args = parser.parse_args()
    XHSAppiumOperate(**vars(args)).run()
